/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package model;

import controller.Traffic;
import java.util.ArrayList;
import java.util.Random;

/**
 * Street block class to process car movements on one road unit.
 * @author Chiaki Sato
 * @since J2SDK 1.6
 * @version 1.0
 */
public class StreetBlock {

    // private instance valiables
    private StreetBlock forwardStreetBlock;
    private ArrayList<Car> arrayStreetBlock;
    private Random randomCarCreation;
    private boolean isStartStreetBlock;
    private float fProbabilityEnterCar;
    private int nRoadLen;

    /**
     * Constructor of road block class that initializes instance valuables.
     * @param forwardStreetBlock Forward road block object if it exists or null
     * @param nRoadLen Road length
     * @param isStartStreetBlock Flag to indicate a start road block in north-west
     * @param nProbabilityEnterCar Probability of a car entering vertical or horizontal street
     */
    public StreetBlock(StreetBlock forwardStreetBlock, int nRoadLen, boolean isStartStreetBlock, float fProbabilityEnterCar){

        int i = 0;
        
        this.forwardStreetBlock = forwardStreetBlock;
        this.isStartStreetBlock = isStartStreetBlock;
        this.fProbabilityEnterCar = fProbabilityEnterCar;
        this.nRoadLen = nRoadLen;

        randomCarCreation = new Random();

        arrayStreetBlock = new ArrayList<Car>(nRoadLen);

        // null clear road block ArrayList
        for(i=0; i<nRoadLen; i++){
            arrayStreetBlock.add(null);
        }        
    }
    
    /**
     * Public function of street block process, that moves cars on one street block.
     * @param nTrafficLightStatus Traffic light status
     */
    public void moveCarsOnStreetBlock(Traffic oTraffic, int nLane, int nStreetLocation, int nTrafficLightStatus){

        // init variables
        Car oCurrentCar = null;
        boolean fGoOneCar = true;
        int i = 0;
        boolean isOvertakeSuccess = false;

        // move cars on one street block
        for (i=nRoadLen-1; i >= 0; i--){

            // check if the position of the car is infront of the traffic light
            if (i == nRoadLen-1){

                // check if there is a car
                if (arrayStreetBlock.get(i) != null){

                    // check the exsitance of a forward street block
                    if (forwardStreetBlock == null){

                        // delete the car from this street block
                        arrayStreetBlock.set(i, null);
                    }
                    else{
 
                        // check the trafic condition of forward street block
                        if(forwardStreetBlock.isEntryOk()){

                            // check if trafic Light is green
                            if (nTrafficLightStatus == Const.LIGHT_GREEN){

                                // move the car to forward street block across an intersection
                                oCurrentCar = arrayStreetBlock.get(i);
                                arrayStreetBlock.set(i, null);
                                forwardStreetBlock.arrayStreetBlock.set(Const.START_POSITIOM_CAR_ON_STREET, oCurrentCar);
                            }
                        }
                    }
                }
            }
            else{
                // check if there is not a car ahead?
                oCurrentCar = arrayStreetBlock.get(i);
                if (oCurrentCar != null && arrayStreetBlock.get(i+1) == null){
                    // Move a car
                    arrayStreetBlock.set(i+1, oCurrentCar);
                    arrayStreetBlock.set(i, null);
                }
                else if (oCurrentCar != null){

                    // try overtaking
                    isOvertakeSuccess = oTraffic.tryOvertake(oCurrentCar, i, nLane, nStreetLocation);
                    if (isOvertakeSuccess){

                        // delete ovaertaked car from original position
                        arrayStreetBlock.set(i, null);
                    }
                }
            }
        }

        // check if it is start road block
        if(isStartStreetBlock == Const.NORTH_WEST){

            float fRandFloat = randomCarCreation.nextFloat();

            if (fProbabilityEnterCar >= fRandFloat){
//            if (nProbabilityEnterCar == Const.ENTER_CAR){

                // create a car
//                fGoOneCar = randomCarCreation.nextBoolean();
//                if (fGoOneCar){
                    enterOneCar();
//                }
            }
        }
    }

    /**
     * Public function to check a available space to move car to the foward street block.
     * @return Determinant of availability to move car foward
     */
    public boolean isEntryOk() {

        if (arrayStreetBlock.get(0) == null){
            return true;
        }
        else{
            return false;
        }
    }

    /**
     * Public function to create a car and put it on start position of a street block.
     */
    public void enterOneCar(){

        Car newCar;

        newCar = new Car();
        arrayStreetBlock.set(Const.START_POSITIOM_CAR_ON_STREET, newCar);
    }

    /**
     * Public function to create an image string to draw one street block with cars.
     * @return Image string to draw one street block with cars
     */
    public String getCarsDrawString(){

        // Init variables
        String stLaneImage = "";
        String stCar = Const.SYMBOL_CAR;
        int i = 0;

        // prepare a cars string to draw
        for (i=nRoadLen-1; i >= 0; i--){
            if (arrayStreetBlock.get(i) != null){
                stCar = arrayStreetBlock.get(i).toString();
                stLaneImage = stCar + stLaneImage;
            }
            else{
                stLaneImage = " " + stLaneImage;
            }
        }

        return stLaneImage;
    }

    /**
     * Public function to check to see if overtaking is possible and execute overtaking.
     * @param oOvertakingCar Overtaking car class object
     * @param nPosCar Original position of overtaking car
     * @return Result of overtaking process
     */
    public boolean overtake(Car oOvertakingCar, int posCar){

        if (arrayStreetBlock.get(posCar+1) != null){

            // failed to overtake because the position already occupied by another car
            return false;
        }
        else{
            // execute overtaking and change the lane diagonally forward
            arrayStreetBlock.set(posCar+1, oOvertakingCar);

            return true;
        }

    }

    /**
     * Public function to get a car object on the specified street position.
     * @return A car object
     */
    public Car getCarOnStreet(int nPosCar){

        Car oCar = null;

        oCar = arrayStreetBlock.get(nPosCar);

        return oCar;
    }

}
